package com.walter.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.walter.common.CommonQuery;
import com.walter.entity.Menu;
import com.walter.entity.Role;
import com.walter.entity.RoleMenu;
import com.walter.entity.UserRole;
import com.walter.exception.LogicException;
import com.walter.mapper.MenuMapper;
import com.walter.mapper.RoleMapper;
import com.walter.mapper.RoleMenuMapper;
import com.walter.mapper.UserRoleMapper;
import com.walter.model.form.SaveRoleForm;
import com.walter.model.vo.MenuVO;
import com.walter.model.vo.RoleVO;
import com.walter.util.Kv;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author ：ch
 * @date ：Created in 2021/5/25
 * @description：
 * @modified By：
 * @version: 1.0
 */
@Service
@Slf4j
public class RoleService {
    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private RoleMenuMapper roleMenuMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Value("${built-in roles}")
    private String initRoles;

    @Value("${built-in adminRole}")
    private String adminRole;

    //init built-in roles
    @Transactional
    public Boolean initBuiltinRoles(){
        String[] roles = initRoles.split(",");//admin|内置超级管理员|内置超级管理员
        for (String item : roles){
            String[] oneRole = item.split("\\|");
            Role role = null;
            role = roleMapper.selectOne(new Role().setName(oneRole[0]));
            if (null == role){
                role = new Role().setName(oneRole[0]).setTitle(oneRole[1]).setDescription(oneRole[2])
                        .setCreateTime(new Date());
                role.insert();
            }
            else {
                role.setName(oneRole[0]).setTitle(oneRole[1]).setDescription(oneRole[2]).updateById();
            }
        }
        return true;
    }

    //find one role by name
    public Role findByName(String name){
        if (StrUtil.isEmpty(name)) {
            log.info("role's name is null");
            throw new LogicException("角色名称为空");
        }
        Role role = roleMapper.selectOne(new Role().setName(name));
        if (null == role){
            log.info("role[name={}] does not exist",name);
            throw new LogicException("名称为" + name + "的角色不存在");
        }
        return role;
    }

    //save
    @Transactional
    public Boolean save(SaveRoleForm form){
        String name = form.getName();
        Integer roleId = form.getId();
        Role role;
        Date now = new Date();
        if (null == roleId){
            List<Role> roles = roleMapper.selectByMap(Kv.by(Role.NAME,name));
            if (CollUtil.isNotEmpty(roles)){
                log.info("role's name can not repeat");
                throw new LogicException("角色名称不允许重复");
            }
            role = new Role();
            BeanUtil.copyProperties(form,role);
            role.setCreateTime(now).insert();
        }
        else {
            role = this.roleIsExist(roleId);
            //不允许修改内置角色
            if (role.getName().equals(adminRole)){
                log.info("user can not update built-in roles[admin]");
                throw new LogicException("不允许修改内置角色admin");
            }
            EntityWrapper<Role> entityWrapper = new EntityWrapper<>();
            entityWrapper.notIn(Role.ID,roleId).eq(Role.NAME,name);
            List<Role> roles = roleMapper.selectList(entityWrapper);
            if (CollUtil.isNotEmpty(roles)){
                log.info("role's name can not repeat");
                throw new LogicException("角色名称不允许重复");
            }
            BeanUtil.copyProperties(form,role);
            role.updateById();
        }
        //
        List<Integer> menuList = form.getMenuList();
        if (CollUtil.isNotEmpty(menuList)){
            roleMenuMapper.deleteByMap(Kv.by(RoleMenu.ROLE_ID,role.getId()));
            roleMenuMapper.addInBatch(Kv.by("menuList",menuList).set("roleId",role.getId()).set("createTime",now));
        }
        return true;
    }

    private Role roleIsExist(Integer roleId){
        if (null == roleId){
            log.info("roleId is null");
            throw new LogicException("角色id为空");
        }
        Role role = roleMapper.selectById(roleId);
        if (null == role){
            log.info("role[id={}] does not exist",roleId.toString());
            throw new LogicException("id为"+roleId.toString()+"的角色不存在");
        }
        return role;
    }

    //findList
    public List<Role> findList(CommonQuery query){
        EntityWrapper<Role> wrapper = new EntityWrapper<>();
        String name = "";
        if (null != query)
            name = query.getText();
        if (!StrUtil.isEmpty(name))
            wrapper.like(Role.NAME,name).or().like(Role.TITLE,name);
        return roleMapper.selectList(wrapper);
    }

    //del
    @Transactional
    public Integer deleteRelation(Integer roleId){
        Role existRole = this.roleIsExist(roleId);
        if (existRole.getName().equals(adminRole)){
            log.info("built-in role can not delete");
            throw new LogicException("系统角色不允许删除");
        }
        Integer t1 = 0,t2 = 0,t3 = 0;
        t1 = userRoleMapper.deleteByMap(Kv.by(UserRole.ROLE_ID,roleId));
        log.info("delete sys_user_role {} record",t1);
        t2 = roleMenuMapper.deleteByMap(Kv.by(RoleMenu.ROLE_ID,roleId));
        log.info("delete sys_role_menu {} record",t2);
        t3 = roleMapper.deleteById(roleId);
        log.info("delete sys_role {} record",t3);
        return t1 + t2 + t3;
    }

    //findRoleDetail
    public RoleVO findRoleDetail(Integer roleId){
        if (null == roleId){
            log.info("roleId is null");
            throw new LogicException("角色id为空");
        }
        Role role = roleMapper.selectById(roleId);
        RoleVO retVal = new RoleVO();
        BeanUtil.copyProperties(role,retVal);
        List<MenuVO> menuVOList = menuMapper.findByRoleId(roleId);
        //need roleBinding's subMenu
        List<RoleMenu> roleMenuList = roleMenuMapper.selectByMap(Kv.by(RoleMenu.ROLE_ID,roleId));
        List<Integer> menuIds = roleMenuList.stream().map(roleMenu -> roleMenu.getMenuId()).collect(Collectors.toList());
        menuVOList.stream().forEach(menuVO -> {
            List<Menu> temp = new ArrayList<>();
            for (Menu menu : menuVO.getSubMenuList()){
                if (menuIds.contains(menu.getId()))
                    temp.add(menu);
            }
            menuVO.setSubMenuList(temp);
        });
        retVal.setMenuIds(menuIds);
        return retVal.setMenuVOList(menuVOList);
    }

    // findRolesByUserId
    public List<Role> findRolesByUserId(Integer userId){
        List<Role> retVal = new ArrayList<>();
        retVal = roleMapper.findByUserId(userId);
        return retVal;
    }

    public List<Integer> findRoleIdsByUserId(Integer userId){
        List<Role> retVal = this.findRolesByUserId(userId);
        return retVal.stream().map(Role :: getId).collect(Collectors.toList());
    }
}
